#pragma once

#include <iostream>
#include <cassert>
#include <vector>
#include <semaphore.h>

static const int gcap=5;

template<class T>
class RingQueue
{
private:
    void P(sem_t& sem)
    {
        int n=sem_wait(&sem);
        assert(n==0);
        (void)n;
    }   
    void V(sem_t& sem)
    {
        int n=sem_post(&sem);
        assert(n==0);
        (void)n;
    } 
public:
    RingQueue(const int& cap=gcap)
    :queue_(cap),cap_(cap)
    {
        //初始化信号量
        int n=sem_init(&spacesem_,0,cap_);
        assert(n==0);
        n=sem_init(&datasem_,0,0);
        assert(n==0);

        pStep_=cStep_=0;
        
        pthread_mutex_init(&pmutex_,nullptr);
        pthread_mutex_init(&cmutex_,nullptr);
    }
    //生产者
    void push(const T& in)
    {
        P(spacesem_);
        //注意！把锁加在信号量里面
        pthread_mutex_lock(&pmutex_);
        queue_[pStep_++]=in;
        pStep_%=cap_;//避免越界
        pthread_mutex_unlock(&pmutex_);
        V(datasem_);
    }

    //消费者
    void pop(T* out)
    {
        P(datasem_);

        pthread_mutex_lock(&cmutex_);
        *out=queue_[cStep_++];
        cStep_%=cap_;
        pthread_mutex_unlock(&cmutex_);

        V(spacesem_);
       
    }

    ~RingQueue()
    {
        sem_destroy(&spacesem_);
        sem_destroy(&datasem_);

        pthread_mutex_destroy(&pmutex_);
        pthread_mutex_destroy(&cmutex_);

    }
private:
    std::vector<T> queue_;
    int cap_;
    sem_t datasem_;//消费者--数据资源
    sem_t spacesem_;//生产者--空间资源
    int pStep_;//生产者数组下标
    int cStep_;//消费者数组下标

    pthread_mutex_t pmutex_;
    pthread_mutex_t cmutex_;

};